#pragma once

#include <glad/glad.h>
#include <sdl.hpp>

#include <nvg.hpp>
#define NANOVG_GL3_IMPLEMENTATION
#include <nanovg_gl.h>

#include <iostream>
#include <string>

#define WND_WIDTH 640
#define WND_HEIGHT 480

namespace gl = sdl::gl;
sdl::Window::Wrapped window_;
gl::Context context_ = nullptr;
NVGcontext *nvg_ = nullptr;

const char* title();
void handleEvent(sdl::event::Event &evt);
void render(NVGcontext *nvg);

int main(int argc, char *argv[]) {
  gl::setAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
  gl::setAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
  gl::setAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);

  auto rst = sdl::init(SDL_INIT_EVERYTHING);
  if (sdl::isFailed(rst)) {
    std::cout << "error init." << std::endl;
    return -1;
  }

  window_ = sdl::Window::create(title(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED
      , WND_WIDTH, WND_HEIGHT, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN);
  if (window_) {
    context_ = sdl::gl::createContext(window_);
  }

  if (context_) {
    if (gladLoadGLLoader((GLADloadproc)gl::getProcAddress)) {
      GLint nStencilBits = 0, nSamples = 0;
      glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER,
          GL_STENCIL, GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE, &nStencilBits);
      glGetIntegerv(GL_SAMPLES, &nSamples);

      int flags = 0;
      if (nStencilBits >= 8)
        flags |= NVG_STENCIL_STROKES;
      if (nSamples <= 1)
        flags |= NVG_ANTIALIAS;
      #if !defined(NDEBUG)
          flags |= NVG_DEBUG;
      #endif
      nvg_ = nvgCreateGL3(flags | NVG_DEBUG);
    }
  }

  if (!nvg_) {
    if (context_) gl::deleteContext(context_);
    if (window_) window_->destroy();
    sdl::quit();
    std::cout << "error create window or opengl context." << std::endl;
    return 0;
  }

  bool quit = false;
  sdl::event::Event evt;
  while (!quit) {
    while (sdl::event::poll(&evt)) {
      if (evt.type == SDL_QUIT) {
        quit = true;
      }
      handleEvent(evt);
    }
    render(nvg_);
    gl::swapWindow(window_);
  }

  gl::deleteContext(context_);
  window_->destroy();
  nvgDeleteGL3(nvg_);

  sdl::quit();
  return 0;
}